package com.xbk.seckill.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.util.concurrent.RateLimiter;
import com.xbk.seckill.common.exception.ErrorCode;
import com.xbk.seckill.common.response.ResponseMessage;
import com.xbk.seckill.common.response.ResponseMessageBuilder;
import lombok.SneakyThrows;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 局部限流器
 *
 * @author xiexu
 * @date 2025/5/10 15:51
 */
@Component
public class BHRequestRateLimitGatewayFilterFactory extends AbstractGatewayFilterFactory<BHRequestRateLimitGatewayFilterFactory.Config> {

    public BHRequestRateLimitGatewayFilterFactory() {
        super(Config.class);
    }

    /**
     * 使用 Guava 提供的本地缓存 Cache，用于存储每个 IP 地址对应的 RateLimiter 实例
     */
    private static final Cache<String, RateLimiter> RATE_LIMITER_CACHE = CacheBuilder
            .newBuilder()
            .maximumSize(1000)
            .expireAfterAccess(1, TimeUnit.HOURS)
            .build();

    /**
     * 过滤器的核心逻辑，根据配置创建 GatewayFilter 实例
     *
     * @param config
     * @return
     */
    @Override
    public GatewayFilter apply(Config config) {
        return new GatewayFilter() {
            @SneakyThrows // 自动抛出受检异常（通常用于简化 Lambda 或匿名类中的异常处理）
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                // 获取远程请求的 IP 地址
                String remoteAddr = Objects.requireNonNull(exchange.getRequest().getRemoteAddress()).getAddress().getHostAddress();
                // 从缓存中获取对应 IP 的 RateLimiter，没有则创建新的 RateLimiter
                RateLimiter rateLimiter = RATE_LIMITER_CACHE.get(remoteAddr, () ->
                        RateLimiter.create(Double.parseDouble(config.getPermitsPerSecond())));
                // 尝试获取一个令牌（非阻塞），获取成功则继续过滤链
                if (rateLimiter.tryAcquire()) {
                    return chain.filter(exchange);
                }
                // 如果令牌获取失败，则表示访问频率过高，返回 429 错误
                ServerHttpResponse response = exchange.getResponse();
                response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
                response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
                // 构造错误响应体（频繁访问错误码和提示信息）
                ResponseMessage<String> responseMessage = ResponseMessageBuilder.build(
                        ErrorCode.FREQUENTLY_ERROR.getCode(),
                        ErrorCode.FREQUENTLY_ERROR.getMesaage()
                );
                // 将响应消息转换为 JSON 并写入响应体
                String responseStr = JSON.toJSONString(responseMessage);
                DataBuffer dataBuffer = response.bufferFactory().wrap(responseStr.getBytes(StandardCharsets.UTF_8));
                return response.writeWith(Mono.just(dataBuffer));
            }
        };
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Collections.singletonList("permitsPerSecond");
    }

    /**
     * 内部静态配置类，定义限流参数
     */
    public static class Config {

        // 每秒可通过的请求数（令牌生成速率）
        private String permitsPerSecond;

        public void setPermitsPerSecond(String permitsPerSecond) {
            this.permitsPerSecond = permitsPerSecond;
        }

        public String getPermitsPerSecond() {
            return this.permitsPerSecond;
        }
    }

}
